//
// Created on 2023/7/6.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#define LOG_TAG "testTag [NATIVE]"

#include "hid_simulator.h"
#include "data_parser.h"
#include <hilog/log.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>
#include "key_code.h"


#define DOWN 1
#define UP 0U

Hid_EmitItem synEvent = {.type = EV_SYN, .code = SYN_REPORT, .value = 0};

static const uint16_t getLinuxKeyCode(int ohosKeyCode) {
    switch(ohosKeyCode) {
    case KEYCODE_UNKNOWN: return KEY_UNKNOWN;
    case KEYCODE_BACK: return KEY_BACKSPACE;
    case KEYCODE_SPACE: return KEY_SPACE;
    case KEYCODE_DEL: return KEY_DELETE;
    case KEYCODE_ESCAPE: return KEY_ESC;
    case KEYCODE_SYSRQ: return KEY_SYSRQ;
    case KEYCODE_ENTER: return KEY_ENTER;
    case KEYCODE_SHIFT_LEFT: return KEY_LEFTSHIFT;
    case KEYCODE_SHIFT_RIGHT: return KEY_RIGHTSHIFT;
    case KEYCODE_BRIGHTNESS_DOWN: return KEY_BRIGHTNESSDOWN;
    case KEYCODE_BRIGHTNESS_UP: return KEY_BRIGHTNESSUP;
    case KEYCODE_MUTE: return KEY_MUTE;
    case KEYCODE_VOLUME_DOWN: return KEY_VOLUMEDOWN;
    case KEYCODE_VOLUME_UP: return KEY_VOLUMEUP;
    case KEYCODE_A: return KEY_A;
    case KEYCODE_B: return KEY_B;
    case KEYCODE_C: return KEY_C;
    case KEYCODE_D: return KEY_D;
    case KEYCODE_E: return KEY_E;
    case KEYCODE_F: return KEY_F;
    case KEYCODE_G: return KEY_G;
    case KEYCODE_H: return KEY_H;
    case KEYCODE_I: return KEY_I;
    case KEYCODE_J: return KEY_J;
    case KEYCODE_K: return KEY_K;
    case KEYCODE_L: return KEY_L;
    case KEYCODE_M: return KEY_M;
    case KEYCODE_N: return KEY_N;
    case KEYCODE_O: return KEY_O;
    case KEYCODE_P: return KEY_P;
    case KEYCODE_Q: return KEY_Q;
    case KEYCODE_R: return KEY_R;
    case KEYCODE_S: return KEY_S;
    case KEYCODE_T: return KEY_T;
    case KEYCODE_U: return KEY_U;
    case KEYCODE_V: return KEY_V;
    case KEYCODE_W: return KEY_W;
    case KEYCODE_X: return KEY_X;
    case KEYCODE_Y: return KEY_Y;
    case KEYCODE_Z: return KEY_Z;
    case KEYCODE_1: return KEY_1;
    case KEYCODE_2: return KEY_2;
    case KEYCODE_3: return KEY_3;
    case KEYCODE_4: return KEY_4;
    case KEYCODE_5: return KEY_5;
    case KEYCODE_6: return KEY_6;
    case KEYCODE_7: return KEY_7;
    case KEYCODE_8: return KEY_8;
    case KEYCODE_9: return KEY_9;
    case KEYCODE_0: return KEY_0;
    default: return KEY_UNKNOWN;
    }
}

static const uint32_t getMscScanCode(int code) {
    switch (code) {
    case KEY_A: return 0x70004;
    case KEY_B: return 0x70005;
    case KEY_C: return 0x70006;
    case KEY_D: return 0x70007;
    case KEY_E: return 0x70008;
    case KEY_F: return 0x70009;
    case KEY_G: return 0x7000A;
    case KEY_H: return 0x7000B;
    case KEY_I: return 0x7000C;
    case KEY_J: return 0x7000D;
    case KEY_K: return 0x7000E;
    case KEY_L: return 0x7000F;
    case KEY_M: return 0x70010;
    case KEY_N: return 0x70011;
    case KEY_O: return 0x70012;
    case KEY_P: return 0x70013;
    case KEY_Q: return 0x70014;
    case KEY_R: return 0x70015;
    case KEY_S: return 0x70016;
    case KEY_T: return 0x70017;
    case KEY_U: return 0x70018;
    case KEY_V: return 0x70019;
    case KEY_W: return 0x7001A;
    case KEY_X: return 0x7001B;
    case KEY_Y: return 0x7001C;
    case KEY_Z: return 0x7001D;
    case KEY_1: return 0x7001E;
    case KEY_2: return 0x7001F;
    case KEY_3: return 0x70020;
    case KEY_4: return 0x70021;
    case KEY_5: return 0x70022;
    case KEY_6: return 0x70023;
    case KEY_7: return 0x70024;
    case KEY_8: return 0x70025;
    case KEY_9: return 0x70026;
    case KEY_0: return 0x70027;
    case KEY_LEFTCTRL: return 0x700e0;
    default:
        return KEY_UNKNOWN;
    }
}

static const std::vector<uint16_t> getCombeKeyCode(int ohosKeyCode) {
    std::vector<uint16_t> codes;
    if(ohosKeyCode < KEYCODE_LEFT_CTRL_ADD_C){
        return codes;
    }
    switch (ohosKeyCode) {
        case KEYCODE_LEFT_CTRL_ADD_C: {
            codes.push_back(KEY_LEFTCTRL);
            codes.push_back(KEY_C);
            break;
        }
        case KEYCODE_LEFT_CTRL_ADD_V: {
            codes.push_back(KEY_LEFTCTRL);
            codes.push_back(KEY_V);
            break;
        }
    }
    return codes;
}

HidSimulator::HidSimulator() {
    injectThread_ = std::make_unique<InjectThread>();
}

void HidSimulator::StartWork() {
    injectThread_->Start();
}

void HidSimulator::ConvertEventData(const EventData &data) {
    if (data.type == EVENT_TYPE_MOVE) {
        ConvertMoveEventData(data);
    } else if (data.type == EVENT_TYPE_MOVE_AND_KEY) {
        ConvertMoveAndKeyEventData(data);
    } else if (data.type == EVENT_TYPE_KEY) {
        ConvertKeyEventData(data);
    } else if (data.type == EVENT_TYPE_DEF_KEY) {
        ConvertDefKeyEventData(data);
    } else if (data.type == EVENT_TYPE_WHEEL_UP) {
        Hid_EmitItem wheelEvent = {.type = EV_REL, .code = REL_WHEEL, .value = 0x1};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, wheelEvent);
        Hid_EmitItem hiEvent = {.type = EV_REL, .code = REL_WHEEL_HI_RES, .value = 0x78};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, hiEvent);
        injectThread_->InjectEvent(DEV_TOUCH_PAD, synEvent);
    } else if (data.type == EVENT_TYPE_WHEEL_DOWN) {
        Hid_EmitItem wheelEvent = {.type = EV_REL, .code = REL_WHEEL, .value = 0xffffffff};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, wheelEvent);
        Hid_EmitItem hiEvent = {.type = EV_REL, .code = REL_WHEEL_HI_RES, .value = 0xffffff88};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, hiEvent);
        injectThread_->InjectEvent(DEV_TOUCH_PAD, synEvent);
    } else if (data.type == EVENT_TYPE_DEF_WHEEL_UP) {
        std::vector<uint16_t> codes = getCombeKeyCode(KEYCODE_LEFT_CTRL_ADD_V);
        for (uint16_t code : codes) {
            Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(code)};
            injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
            Hid_EmitItem event = {.type = EV_KEY, .code = code, .value = DOWN};
            injectThread_->InjectEvent(DEV_KEYBOARD, event);
            injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
        }
        for (int i = codes.size() - 1; i >= 0; i--) {
            Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(codes[i])};
            injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
            Hid_EmitItem event = {.type = EV_KEY, .code = codes[i], .value = UP};
            injectThread_->InjectEvent(DEV_KEYBOARD, event);
            injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
        }
    } else if (data.type == EVENT_TYPE_DEF_WHEEL_DOWN) {
        std::vector<uint16_t> codes = getCombeKeyCode(KEYCODE_LEFT_CTRL_ADD_C);
        for (uint16_t code : codes) {
            Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(code)};
            injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
            Hid_EmitItem event = {.type = EV_KEY, .code = code, .value = DOWN};
            injectThread_->InjectEvent(DEV_KEYBOARD, event);
            injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
        }
        for (int i = codes.size() - 1; i >= 0; i--) {
            Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(codes[i])};
            injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
            Hid_EmitItem event = {.type = EV_KEY, .code = codes[i], .value = UP};
            injectThread_->InjectEvent(DEV_KEYBOARD, event);
            injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
        }
    }
    injectThread_->Sync();
    eventData_ = data;
}

void HidSimulator::ConvertMoveEventData(const EventData &data) {
    if (data.relX != 0) {
        Hid_EmitItem event = {.type = EV_REL, .code = REL_X, .value = data.relX};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, event);
    }
    if (data.relY != 0) {
        Hid_EmitItem event = {.type = EV_REL, .code = REL_Y, .value = data.relY};
        injectThread_->InjectEvent(DEV_TOUCH_PAD, event);
    }
    injectThread_->InjectEvent(DEV_TOUCH_PAD, synEvent);
}

void HidSimulator::ConvertDefKeyEventData(const EventData &data) {
    if (data.keyVal < KEYCODE_LEFT_CTRL_ADD_C) {
        Hid_EmitItem event = {.type = EV_KEY, .code = getLinuxKeyCode(data.keyVal), .value = (data.isDown ? DOWN : UP)};
        injectThread_->InjectEvent(DEV_KEYBOARD, event);
        injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
    } else {
        std::vector<uint16_t> codes = getCombeKeyCode(data.keyVal);
        if (data.isDown) {
            for (uint16_t code : codes) {
                Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(code)};
                injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
                Hid_EmitItem event = {.type = EV_KEY, .code = code, .value = (data.isDown ? DOWN : UP)};
                injectThread_->InjectEvent(DEV_KEYBOARD, event);
                injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
            }
        } else {
            for (int i = codes.size() - 1; i >=0 ; i--) {
                Hid_EmitItem scanEvent = {.type = EV_MSC, .code = MSC_SCAN, .value = getMscScanCode(codes[i])};
                injectThread_->InjectEvent(DEV_KEYBOARD, scanEvent);
                Hid_EmitItem event = {.type = EV_KEY, .code = codes[i], .value = (data.isDown ? DOWN : UP)};
                injectThread_->InjectEvent(DEV_KEYBOARD, event);
                injectThread_->InjectEvent(DEV_KEYBOARD, synEvent);
            }
        }
        
    }
}

void HidSimulator::ConvertKeyEventData(const EventData &data) {
    Hid_EmitItem event = {.type = EV_KEY, .code = (uint16_t) data.keyVal, .value = (data.isDown ? DOWN : UP)};
    injectThread_->InjectEvent(DEV_TOUCH_PAD, event);
    injectThread_->InjectEvent(DEV_TOUCH_PAD, synEvent);
}

void HidSimulator::ConvertMoveAndKeyEventData(const EventData &data) {
    ConvertMoveEventData(data);
    ConvertKeyEventData(data);
}